package ai.easy.robot.task

import com.easy.robot.task.TaskContext
import kotlinx.coroutines.experimental.*
import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue

//import kotlinx.coroutines.experimental.TimeoutException

/**
 * 管理子任务队列的运行
 */
class SubTaskQueueManager(val ctx: TaskContext) {


    val taskCount: Int
        get() = queue.size

    val queue: BlockingQueue<ISubTask> = LinkedBlockingQueue<ISubTask>()

    fun add(subTask: ISubTask) {
        ctx.pool.log("添加子任务${subTask}")
        queue.offer(subTask)
    }


    internal var work: Deferred<Boolean>? = null


    internal var isFinished = false

    /**
     * 开始运行队列
     * @param whenFinish 队列结束时回调
     */
    private var currJob: Deferred<Boolean>? = null
    private var isPause: Boolean = false
    fun start(whenFinish: () -> Unit) {
        work = async(ctx.cctx) {
            //
            var ok = true
            while (isActive && queue.size > 0 && ok) {
                //暂停时挂起
                if (isPause) {
                    delay(100)
                    continue
                }
                val sub = queue.poll()
                val t = sub.timeout().toLong()
                val timeout = if (t < 100L) 100L else t
                var is_timeout = false
                try {
                    withTimeout(t) {
                        currJob = async(context) {
                            sub.run(SubTaskParallelManager(ctx.cctx))
                        }
                        ok = currJob?.await() ?: false
                    }
                } catch (e: Throwable) {
                    e.printStackTrace()
                    is_timeout = true
                } finally {
                    val r = sub.onCancel(is_timeout)
                    ok = if (is_timeout) r else ok
                }
            }
            //
            currJob = null
            isFinished = true
            whenFinish()
            true
        }
    }

    /**
     * 强制取消
     */
    fun forceCancel() {
        //work?.
        work?.cancel()
        isFinished = true
    }

    fun pauseSubTasks() {
        isPause = true
        currJob?.let {
            runBlocking {
                if (it.isActive) {
                    it.await()
                }
            }
        }
    }

    fun resumeSubTasks() {
        isPause = false
    }

    fun delayMs(ms: Int) {
        runBlocking(ctx.cctx) {
            delay(ms.toLong())
        }
    }
}